package com.nulldev.util.uri.formIO;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.HttpsURLConnection;

import com.nulldev.util.java.DataSet;
import com.nulldev.util.math.MathUtil;
import com.nulldev.util.uri.URIUtil2.IO.Entry;

public class MultipartBuilder {
	private final String boundary;
    private static final String NEW_LINE = "\r\n";
    private URLConnection conn;
    private String charset = "UTF-8";
    private OutputStream outputStream;
    private PrintWriter writer;
 
    public MultipartBuilder(String requestURL, String token) throws IOException {             
        // creates a unique boundary based on time stamp
        boundary = "---" + System.currentTimeMillis() + "---";
         
        URL url = new URL(requestURL);
        conn = (HttpsURLConnection) url.openConnection();
        conn.setUseCaches(false);
        conn.setDoOutput(true);
        conn.setDoInput(true);     
        conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + boundary);
        conn.setRequestProperty("Authorization", "Basic "+token);
        
        outputStream = conn.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),true);
    }
    
    public MultipartBuilder(String requestURL, final Entry... entries) throws IOException {             
        // creates a unique boundary based on time stamp
        boundary = "---" + System.currentTimeMillis() + "---";
         
        URL url = new URL(requestURL);
        conn = (HttpsURLConnection) url.openConnection();
        
    	for (final Entry entry : entries) {
    		conn.setRequestProperty(entry.getKey(), entry.getValue());
    	}
        
        conn.setUseCaches(false);
        conn.setDoOutput(true);
        conn.setDoInput(true);     
        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
        
        outputStream = conn.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),true);
    }
    
    public MultipartBuilder(HttpsURLConnection conn, String token) throws IOException {             
        // creates a unique boundary based on time stamp
        boundary = "---" + System.currentTimeMillis() + "---";
        
        this.conn = conn;
        
        
        conn.setUseCaches(false);
        conn.setDoOutput(true);
        conn.setDoInput(true);     
        conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + boundary);
        conn.setRequestProperty("Authorization", "Basic " + token);
        
        outputStream = conn.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),true);
    }
    
    public MultipartBuilder(HttpURLConnection conn) throws IOException {             
        // creates a unique boundary based on time stamp
        boundary = "---" + System.currentTimeMillis() + "---";
        
        this.conn = conn;
        conn.setUseCaches(false);
        conn.setDoOutput(true);
        conn.setDoInput(true);     
        conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + boundary);
        
        outputStream = conn.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),true);
    }
    
    public void addFormField(String name, String contentType, String value) {
        writer.append("--" + boundary).append(NEW_LINE);
        writer.append("Content-Disposition: form-data; name=\"" + name + "\";")
                .append(NEW_LINE);
        writer.append("Content-Type: ").append(contentType).append(NEW_LINE);
        writer.append(NEW_LINE);
        writer.append(value).append(NEW_LINE);
        writer.flush();
    }
 
    public void addFormField(String name, String fileName, String contentType, String value) {
        writer.append("--" + boundary).append(NEW_LINE);
        writer.append("Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + fileName + "\"")
                .append(NEW_LINE);
        writer.append("Content-Type: ").append(contentType).append(NEW_LINE);
        writer.append(NEW_LINE);
        writer.append(value).append(NEW_LINE);
        writer.flush();
    }
    
    public DataSet<String, Integer> finish() throws IOException {
    	
        //List<String> response = new ArrayList<String>();
    	final StringBuilder response = new StringBuilder();
 
        writer.append(NEW_LINE).flush();
        writer.append("--" + boundary + "--").append(NEW_LINE);
        writer.close();
 
        int status = (conn instanceof HttpURLConnection ? ((HttpURLConnection) conn).getResponseCode() 
        		: ((HttpsURLConnection) conn).getResponseCode());
        if (MathUtil.between(status, 400, 500)) {
        	return new DataSet<String, Integer>("failed", status);
        }
        if (status == HttpURLConnection.HTTP_OK) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();
            if (conn instanceof HttpsURLConnection) {
            	((HttpsURLConnection) conn).disconnect();
            }else {
            	((HttpURLConnection) conn).disconnect();
            }
        } else {
            throw new IOException("Server returned status: " + status);
        }     
        return new DataSet<String, Integer>(response.toString(), status);
    }
}
